from wormbane.FieldOfView import FieldOfView
from wormbane.generate_level import generate_level
from wormbane.Item import Boulder
from wormbane.language import format_message
from wormbane.Level import Level
from wormbane.Monster import Monster
from wormbane.move import MoveError, move_item, move_monster
from wormbane.save import load_level, save_level
import random


def random_floor_tile(level):
    room = random.choice(level.rooms)
    x = random.randrange(room.bounds.min.x + 1, room.bounds.max.x - 1)
    y = random.randrange(room.bounds.min.y + 1, room.bounds.max.y - 1)
    return level.tiles[x][y]


class Game(object):

    def __init__(self):
        self.messages = []
        self.current_level = generate_level()
        self.level_nums = set([self.current_level.num])
        self.light = FieldOfView(self.current_level.size)
        self.field_of_view = FieldOfView(self.current_level.size)
        self.hero = Monster()
        self.hero.race = 'elf'
        self.hero.color = 'green'
        self.hero.speed = 1.5
        self.hero.protection = 10.0
        move_monster(self, self.hero, self.current_level.stair_up_tile)
        self.current_level.push_monster(self.hero)
        for i in xrange(random.randrange(6, 10)):
            monster = Monster()
            monster.race = 'orc'
            monster.color = 'red'
            try:
                move_monster(self, monster,
                             random_floor_tile(self.current_level))
            except MoveError:
                pass
            else:
                self.current_level.push_monster(monster)
        for i in xrange(random.randrange(6, 10)):
            move_item(self, Boulder(), random_floor_tile(self.current_level))

    def __blocked(self):
        tiles = self.current_level.tiles
        def blocked(x, y):
            try:
                tile = tiles[x][y]
            except IndexError:
                return True
            else:
                return (tile.top_item and not tile.top_item.passable
                        or tile.feature and not tile.feature.passable)
        return blocked

    def update_light(self):
        self.light.clear()
        self.light.add(self.hero.pos.x, self.hero.pos.y, 3.5,
                       self.__blocked())

    def update_field_of_view(self):
        self.field_of_view.clear()
        self.field_of_view.add(self.hero.pos.x, self.hero.pos.y,
                               max(self.current_level.size), self.__blocked())

    def change_level(self, num):
        dir = 'down' if num > self.current_level.num else 'up'
        move_monster(self, self.hero, None)
        save_level(self.current_level)
        if num in self.level_nums:
            self.current_level = load_level(num)
        else:
            self.current_level = generate_level()
            self.current_level.num = num
            self.level_nums.add(num)
        move_monster(self, self.hero,
                     self.current_level.stair_up_tile if dir == 'down'
                     else self.current_level.stair_down_tile)

    def write(self, *args):
        if len(args) == 1:
            # Plain message.
            message = args[0]
        else:
            message = format_message(observer=self.hero, *args)
        self.messages.append(message)
